/* -----------------
* brief
* 1. this is code gen by tools
 */

package service

import (
	"errors"
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"github.com/mjiulee/lego"
	"saas_sys_base/common"
	"time"

	"github.com/chanxuehong/wechat/mp/oauth2"
	// "saas_sys_base/config"
	// configService "saas_sys_base/modules/config/service"
	wechatService "saas_sys_base/modules/wechat/service"
	
	. "saas_sys_base/modules/user/models"
)

type WxUserService struct {
	UserService
	appTenantUserRelService AppTenantUserRelService

	// add your model here
	tbWxUser WxUser

	//configService configService.ConfigService
	wechatService wechatService.WechatService
}

var _ UserServiceInterface = (*WxUserService)(nil)

func (t *WxUserService) ListWxUser(keyword string, page, psize int, orderField, order string) ([]map[string]string, int64, error) {
	// 业务查询
	queryMap := map[string]interface{}{
		"table":  map[string]string{"table": "tb_wx_user", "alias": "t1"},
		"fields": []string{"t1.*"},
		"join":   []map[string]string{
			// map[string]string{"table": "tb_xx as t2", "on": "t2.xid = t1.id"},
		},
		"where": []lego.QMapWhereField{
			{"t1.if_del", "=", 0, "AND", false},
		},
		"search": map[string]string{
			//"t1.id": req.Keyword,
		},
		"orders": []string{"t1.id asc"},
		"page": map[string]int{
			"page":  page,
			"psize": psize,
		},
	}

	if orderField != "" && order != "" {
		orderStr := fmt.Sprintf("t1.%s %s", orderField, order)
		queryMap["orders"] = []string{orderStr, "t1.cdate asc"}
	}

	return lego.QueryListByMap(queryMap)
}

/* 根据id获取记录
 * -----------------
 */
func (t *WxUserService) GetWxUserById(id int64) *WxUser {
	return t.tbWxUser.RecodeById(id)
}

func (t *WxUserService) GetWxUserByUionId(uionId string) (*WxUser) {
	return t.tbWxUser.RecodeByUnionId(uionId)
}

/* 添加
 * -----------------
 */
func (t *WxUserService) SaveWxUser(item2add *WxUser) bool {
	return t.tbWxUser.AddRecode(item2add)
}

/* 删除(硬删除)*/
func (t *WxUserService) DelWxUserById(id int64) bool {
	return t.tbWxUser.DelRecodeById(id)
}

/* 更新
 * -----------------*/
func (t *WxUserService) UpdateWxUser(rc *WxUser) bool {
	return t.tbWxUser.UpdateRecode(rc)
}

//自定义函数
func (t *WxUserService) userLogin(whoApp common.Who, code string, EncryptedData, iv string) (user *WxUser, tokenString string, err error) {

	var wxrspSessionInfo *oauth2.SessionInfo
	// 调微信接口获取用户openid
	//wxHelper := wxhelper.WechatHelper{}
	//appid, appsecret := GetWxconfig(kUserAppIdConfig)
	//appid := config.Wechat.WX_APPID
	//appsecret := config.Wechat.WX_APPSECRET
	//wxrsp, err := wxHelper.GetSessionKey(appid, appsecret, code)

	//mp :=oauth2.NewEndpoint(appid, appsecret)
	mp, weappid := t.wechatService.GetEndpointFromConfig(whoApp)
	if mp == nil {
		return nil, "", errors.New("读取小程序配置出错")
	}


	wxrspSession, err := oauth2.GetSession(mp, code)
	if err != nil {
		return nil, "", err
	}

	if EncryptedData != "" {
		wxrspSessionInfo, err = oauth2.GetSessionInfo(EncryptedData, wxrspSession.SessionKey, iv) // TODO对比和oauth2.GetSession的区别// TODO对比和oauth2.GetSession的区别
		if err != nil {
			return nil, "", fmt.Errorf("decrypt user data err<%s>", err.Error())
		}
	}

	//lego.LogInfo(wxrsp)
	userOpenId := wxrspSession.OpenId   //gjson.Get(wxrsp, "openid").String()
	userUnionId := wxrspSession.UnionId //gjson.Get(wxrsp, "unionId").String()
	if userOpenId == "null" { // TODO 这里写== ”null“是不是有问题
		return nil, "", errors.New("参数错误")
	}

	dbuser := t.tbWxUser.RecodeByOpenId(userOpenId /*, weappid*/)
	if dbuser == nil { // 新用户
		//data["type"] = 2
		// 获取用户基本信息
		dbuser = new(WxUser)
		dbuser.OpenId = userOpenId
		dbuser.UnionId = userUnionId
		dbuser.WeappId = weappid
		dbuser.SessionKey = wxrspSession.SessionKey //更新wx session key

		if wxrspSessionInfo != nil {
			dbuser.OpenId = wxrspSessionInfo.OpenId
			dbuser.NickName = wxrspSessionInfo.Nickname
			dbuser.Gender = wxrspSessionInfo.Gender
			dbuser.Language = wxrspSessionInfo.Language
			dbuser.City = wxrspSessionInfo.City
			dbuser.Province = wxrspSessionInfo.Province
			dbuser.Country = wxrspSessionInfo.Country

			dbuser.AvatarUrl = wxrspSessionInfo.AvatarUrl //TODO 后续把头像上传oss
			dbuser.UnionId = wxrspSessionInfo.UnionId

		}
		if false == t.tbWxUser.AddRecode(dbuser) {
			return nil, "", errors.New("登陆失败")
		}
	} else {
		dbuser.OpenId = userOpenId
		dbuser.UnionId = userUnionId
		dbuser.WeappId = weappid
		dbuser.SessionKey = wxrspSession.SessionKey //更新wx session key
		/*if len(dbuser.NickName) > 0 {
			data["type"] = 1
			data["phone"] = dbuser.Mobile
		} else {
			data["type"] = 2
			data["phone"] = ""
		}*/
		dbuser.SessionKey = wxrspSession.SessionKey
		if wxrspSessionInfo != nil {

			//DONE:已处理此条建议 先不更新这些数据，以后需要更新可以开放出来 done
			dbuser.OpenId = wxrspSessionInfo.OpenId
			dbuser.NickName = wxrspSessionInfo.Nickname
			dbuser.Gender = wxrspSessionInfo.Gender
			dbuser.Language = wxrspSessionInfo.Language
			dbuser.City = wxrspSessionInfo.City
			dbuser.Province = wxrspSessionInfo.Province
			dbuser.Country = wxrspSessionInfo.Country

			dbuser.AvatarUrl = wxrspSessionInfo.AvatarUrl
			/*dbuser.UnionId = wxrspSessionInfo.UnionId*/
		}
		t.tbWxUser.UpdateRecode(dbuser)

	}

	// 登陆成功，创建json-web-token 生成Token
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"uid": fmt.Sprintf("%d", dbuser.Id), // 这个地方，他会转成float64，很奇葩
		"exp": time.Now().Add(time.Minute * 30).Unix(),
	})

	tokenString, err = token.SignedString([]byte(lego.TokenSecretKey()))
	if err != nil {
		return nil, "", errors.New("token生成失败")
	}

	return dbuser, tokenString, nil
}

func (t *WxUserService) UserLogin(whoAppTenant common.Who, code string, EncryptedData, iv string/*, MiniAppId int64, tid int64*/) (user *LoginUser, tokenString string, err error) {

	wxUser, wxTokenString, err := t.userLogin(whoAppTenant, code, EncryptedData, iv) //微信登录，微信用户在这个表中只有唯一一条记录
	if err != nil {
		return nil, "", err
	}

	User, err := t.ThirdLogin(wxUser.Id) //这里为了给每个user维护一个系统内唯一的用户记录，用户在多个租户处登录，这里也只有一个用户记录
	if err != nil {
		return nil, "", err
	}

	//登录后，使用得到的Uid，组合成一个表示user的who对象
	whoUser := common.NewWho(whoAppTenant.TenantId, whoAppTenant.MiniAppId, User.Id)
	_, userRelTokenString, err := t.appTenantUserRelService.userLogin(*whoUser /*MiniAppId, tid, sysUser.Id*/) //这个登录就是多租户的关系表，建立appid、租户id、Uid
	if err != nil {
		return nil, "", err
	}

	wxTokenString = wxTokenString //暂时不需要wx token

	user = new(LoginUser)
	user.User = User
	user.WxUser = wxUser
	return user, userRelTokenString, nil
}

func (t *WxUserService) CheckToken(passToken string, timestamp string) (userwho *common.Who, loginuser *LoginUser, err error) {
	userRel, err := t.appTenantUserRelService.CheckUserToken(passToken, timestamp)
	if err != nil {
		return nil, nil, err
	}

	sysUser := t.GetUserById(userRel.Uid)
	if sysUser == nil {
		return nil, nil, errors.New("找不到用户")
	}

	wxUser := t.GetWxUserById(sysUser.WxUid)
	if sysUser == nil {
		return nil, nil, errors.New("找不到用户")
	}

	loginuser = new(LoginUser)
	loginuser.User = sysUser
	loginuser.WxUser = wxUser

	userWho := &common.Who{
		TenantId:  userRel.TenantId,
		MiniAppId: userRel.MiniAppId,
		Uid:       userRel.Uid,
	}
	return userWho, loginuser, nil

}

func (t *WxUserService) ThirdLogin(wxUid int64) (UnionUser *User, err error) {
	//查看是否注册过，如果没有
	var user *User
	user = t.UserService.tbUser.RecodeByWxUid(wxUid)

	if user == nil {
		var item2add User
		item2add.WxUid = wxUid
		if false == t.tbUser.AddRecode(&item2add) {
			return nil, errors.New("userLogin failed in UserService userLogin")
		}

		user = &item2add
	}

	return user, nil
}

func (t *WxUserService) decrptPhone(EncryptedData, sessionKey, iv string) (*oauth2.PhoneInfo, error){
	phoneInfo, err := oauth2.GetDecryptPhoneInfo(EncryptedData, sessionKey, iv) // TODO对比和oauth2.GetSession的区别// TODO对比和oauth2.GetSession的区别
	if err != nil {
		return nil, err
	}
	return phoneInfo, nil
}

func (t *WxUserService) DecrptAndSavePhoneByWho(who *common.Who, EncryptedData, iv string) (*oauth2.PhoneInfo, error){
	sysUser := t.GetUserById(who.Uid)
	if sysUser == nil {
		return nil, errors.New("找不到用户")
	}

	wxUser := t.GetWxUserById(sysUser.WxUid)
	if sysUser == nil {
		return nil, errors.New("找不到用户")
	}

	phoneInfo, err := oauth2.GetDecryptPhoneInfo(EncryptedData, wxUser.SessionKey, iv) // TODO对比和oauth2.GetSession的区别// TODO对比和oauth2.GetSession的区别
	if err != nil {
		return nil, err
	}

	rcWxUser := new(WxUser)
	rcWxUser.Id = wxUser.Id
	rcWxUser.PhoneNumber = phoneInfo.PhoneNumber
	t.tbWxUser.UpdateRecode(rcWxUser)

	return phoneInfo, nil
}

func (t *WxUserService) SavePhoneByWho(who common.Who, PhoneNumber string) (error){
	sysUser := t.GetUserById(who.Uid)
	if sysUser == nil {
		return errors.New("找不到用户")
	}

	wxUser := t.GetWxUserById(sysUser.WxUid)
	if sysUser == nil {
		return errors.New("找不到用户")
	}

	rcWxUser := new(WxUser)
	rcWxUser.Id = wxUser.Id
	rcWxUser.PhoneNumber = PhoneNumber
	t.tbWxUser.UpdateRecode(rcWxUser)

	return nil
}

func (t *WxUserService) GetUserByUionId(uionId string) (*User) {
	wxUser := t.GetWxUserByUionId(uionId)
	if wxUser == nil {
		return nil
	}

	userdb := t.UserService.GetUserByWxUid(wxUser.Id)
	return userdb
}

func (t *WxUserService) GetWxUserByUid(uid int64) (*WxUser) {
	user := t.GetUserById(uid)
	if user == nil {
		return nil
	}

	wxuser := t.GetWxUserById(user.WxUid)
	return wxuser
}